"""
Configure the docker container within a script with user-specific settings.

Such as synchronization of the editor configs, git configs, package-manager mirrors, etc.
"""

import os
import tarfile
import io
from typing import Callable, Literal, Optional, TypedDict
from docker import DockerClient


class MirrorsConfig(TypedDict):
    """
    A dictionary of package-manager mirrors.
    """

    pip: str  # e.g. https://pypi.tuna.tsinghua.edu.cn/simple
    npm: str  # e.g. https://registry.npmmirror.com
    apt: str  # e.g. mirrors.ustc.edu.cn (Do not start with http:// or https://)


PACKAGE_MANAGER_TYPES = Literal[
    "apt", "yum", "pacman", "apk", "dnf", "zypper", "xbps", "emerge", ""
]


class ContainerInfoReader:
    def __init__(self, docker_cli: DockerClient, container: str) -> None:
        self.docker_cli = docker_cli
        self.container = self.docker_cli.containers.get(container)

    def get_files_content(
        self,
        file_path: str,
        encoding: str = "utf-8",
        errors="replace",
        filename_filter=None,
    ) -> tuple[list[tuple[str, str]], Optional[Exception]]:
        """
        Get the content of files under a directory or a single file (len(ret[0])==1) in the container.

        :return: Tuple of (content, error).
        """
        assert not file_path.endswith("/"), "file_path should not end with '/'"
        if filename_filter is None:
            filename_filter = lambda x: True
        try:
            # 获取归档文件
            archive, _ = self.container.get_archive(file_path)

            # 初始化文件内容列表
            file_contents = []

            # 遍历生成器，逐个读取文件内容
            for chunk in archive:
                # 解析归档文件中的每个文件
                # 注意：这里假设归档文件是 tar 格式，需要使用 tarfile 模块解析
                # 将 chunk 转换为文件对象
                file_obj = io.BytesIO(chunk)

                # 打开 tar 文件
                with tarfile.open(fileobj=file_obj, mode="r:") as tar:
                    for member in tar.getmembers():
                        # 读取文件内容
                        extracted = tar.extractfile(member)
                        if extracted is not None:
                            file_content = extracted.read().decode(
                                encoding, errors=errors
                            )
                            filename = os.path.join(
                                os.path.dirname(file_path), member.name
                            )
                            if filename_filter(filename):
                                # 存储为 (文件名, 文件内容) 的元组
                                file_contents.append(
                                    (
                                        filename,
                                        file_content,
                                    )
                                )
            if len(file_contents) == 0:
                raise ValueError(f"No file or directory found for {file_path}.")
            return file_contents, None
        except Exception as e:
            return [], e

    def get_system_package_manager(self) -> PACKAGE_MANAGER_TYPES:
        """
        Get the system package manager.

        empty string means unknown package manager
        """
        os_info = self.get_os_info()
        os_release_id = os_info.get("ID", "UNDEFINED")
        pkg_manager_mappings: dict[str, PACKAGE_MANAGER_TYPES] = {
            "debian": "apt",
            "ubuntu": "apt",
            "centos": "yum",
            "fedora": "dnf",
            "arch": "pacman",
            "alpine": "apk",
            "rhel": "yum",
            "opensuse": "zypper",
            "sles": "zypper",
            "oracle": "yum",
            "amzn": "yum",
            "gentoo": "emerge",
            "void": "xbps",
            "deepin": "apt",
        }
        return pkg_manager_mappings.get(os_release_id, "")

    def get_os_info(self):
        """
        获取容器的操作系统信息和版本。
        通过执行 `cat /etc/os-release` 命令并解析输出结果。
        """
        exec_result = self.container.exec_run(cmd="cat /etc/os-release")

        if exec_result.exit_code != 0:
            raise RuntimeError(
                f"Failed to retrieve OS info: {exec_result.output.decode()}"
            )

        os_info = {}
        for line in exec_result.output.decode().splitlines():
            key, value = line.split("=", 1)
            os_info[key.strip()] = value.strip().strip('"')

        return os_info


class MirrorsConfigWriter:
    def __init__(
        self,
        docker_cli: DockerClient,
        docker_container: str,
        mirrors_config: MirrorsConfig,
    ):
        self.mirrors_config = mirrors_config
        self.docker_cli = docker_cli
        self.docker_container = docker_container

    def write_mirrors_config(self):

        reader = ContainerInfoReader(self.docker_cli, self.docker_container)
        mgr = reader.get_system_package_manager()

        def apt_handler():
            ret, err = reader.get_files_content("/etc/apt/sources.list")
            # print(ret, err)
            if err is None:
                file_content = ret[0][1]
                print(file_content)
            else:
                ret, err = reader.get_files_content(
                    "/etc/apt/sources.list.d",
                    filename_filter=lambda name: name.endswith(".sources"),
                )

                if err is None:
                    file_content = ret[0][1]
                    """
                    file_content is like:

                    Types: deb
                    URIs: http://mirrors.ustc.edu.cn/debian-security
                    Suites: bookworm-security
                    Components: main contrib non-free non-free-firmware
                    Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg
                    """
                    apt_config_data = {}
                    for line in file_content.split("\n"):
                        splitted = list(filter(
                            lambda s: s != "", map(lambda s: s.strip(), line.split(":", maxsplit=1))
                        ))
                        if len(splitted) == 2:
                            key, value = splitted
                            apt_config_data[key] = value
                    URIs = apt_config_data.get("URIs", "")
                    print(apt_config_data)
                    # 获取URIs中的hostname
                    from urllib.parse import urlparse

                    hostname = urlparse(URIs).hostname if URIs else ""
                    print("Hostname:", hostname)

                    print("file_content", file_content)
                    replaced_content = file_content.replace(hostname, self.mirrors_config["apt"])
                    print("Replaced Content:", replaced_content)
                else:
                    pass
                # print(ret, err)

        managers_handler: dict[PACKAGE_MANAGER_TYPES, Callable] = {
            "apt": apt_handler,
            # "yum": yum_handler,
        }
        handler = managers_handler.get(mgr)
        if handler:
            handler()
        # self.docker_cli.containers.get(self.docker_container).get_archive("")
